package search.dynamic;

import java.util.LinkedList;
import java.util.Vector;
import agents.Agent;
import env.Action;
import env.Orientation;
import env.Tile;

public class dynamic implements Searchable {

	Agent a;
	Vector<Tile> flags = null;
	LinkedList<Tile> rout = null;
	
	public dynamic() {
	}
	
	@Override
	public Action nextAction() {
		if (this.rout == null || this.rout.isEmpty()) {
			rePlan();
			if (flags.size() == 0)
				return Action.left;
		}
		Tile t = this.rout.peek();
		Action act = getAction(a.getOrientation(),a.getRow(),a.getCol(),t.getRow(),t.getCol());
		if (act.equals(Action.fwd))
			this.rout.poll();
		return act;
	}

	@Override
	public void rePlan() {
		this.flags = this.getFlags();
		Vector<Planner> p = new Vector<Planner>();
		for(Tile t : this.flags ) {
			p.add(new Planner(this.a.getEnv(),t));
		}
		System.out.println("found flags: "+this.flags.size());
		PermutationGenerator perm = new PermutationGenerator(this.flags.size());
		int min = Integer.MAX_VALUE;
		int[] bestPerm = null;
		while (perm.hasMore()) {
			int[] currperm = perm.getNext();
			int currScore = getScore(p,currperm);
			for (int i=0;i<currperm.length;++i)
				System.out.print(currperm[i]+" ");
			System.out.println("score: "+currScore);
			if (currScore <= min) {
				min = currScore;
				bestPerm = currperm.clone();
				System.out.println("boo");
			}
		}
		rout = new LinkedList<Tile>();
		if (bestPerm == null)
			rout = null;
		System.out.println("i want the flag in:");
		for (int i=0;i<bestPerm.length;++i) {
			System.out.print(bestPerm[i]+"> "+p.get(bestPerm[i]).getSrc().getRow()+" , "+p.get(bestPerm[i]).getSrc().getCol()+"  *  ");
			
		}
		System.out.println();
		
		this.rout = p.get(bestPerm[0]).getRout(a.getRow(),a.getCol());
		LinkedList<Tile> r2 = this.rout;
		System.out.println("myway");
		for (int i=0;i<r2.size();++i) {
			Tile ttt = r2.pollLast();
			System.out.print(i+"> "+ttt.getRow()+" , "+ttt.getCol()+"  *  ");
			
		}
		System.out.println();
		this.rout.toArray();
	}

	@Override
	public void setAgent(Agent agent) {
		this.a = agent;
	}
	
	private int getScore(Vector<Planner> p, int[] path) {
		int score = 0;
		Tile prev = a.getEnv().map[a.getRow()][a.getCol()];
		for (int i=0;i<path.length;++i) {
			score += p.get(path[i]).getScore(prev.getRow(),prev.getCol());
			prev = p.get(path[i]).getSrc();
		}
		return score;
	}
	
	private Vector<Tile> getFlags() {
		Vector<Tile> flags = new Vector<Tile>();
		for (int i=0;i<a.getEnv().rows;++i)
            for (int j=0;j<a.getEnv().cols;++j)
                if (a.getEnv().map[i][j].hasFlag())
                    flags.add(a.getEnv().map[i][j]);
		return flags;
	}
	
	private static Action getAction(Orientation o, int oRow,int oCol, int dRow, int dCol) {
		Orientation needed = getOrientation(oRow,oCol,dRow,dCol);
		if (o.equals(needed))
			return Action.fwd;
		if (
				
		    (o.equals(Orientation.North) & needed.equals(Orientation.South))
		    | (o.equals(Orientation.South) & needed.equals(Orientation.North))
		    | (o.equals(Orientation.East) & needed.equals(Orientation.West))
		    | (o.equals(Orientation.West) & needed.equals(Orientation.East))	
		)
			return Action.left;
		switch(o) {
			case North: {
				if (needed.equals(Orientation.East))
					return Action.right;
				return Action.left;
			}
			case South: {
				if (needed.equals(Orientation.East))
					return Action.left;
				return Action.right;
			}
			case East: {
				if (needed.equals(Orientation.North))
					return Action.left;
				return Action.right;
			}
			case West: {
				if (needed.equals(Orientation.North))
					return Action.right;
				return Action.left;
			}
			default : return null;		
		}
	}

	private static Orientation getOrientation(int orow,int ocol,int drow,int dcol) {
	if (orow == drow) {
		if (dcol < ocol) {
			return Orientation.West;
		}
		else {
			return Orientation.East;
		}
	}
	else {
		if (drow < orow) {
			return Orientation.North;
		}
		else {
			return Orientation.South;
		}
	}
}


}
